package spring.aop.advice;

import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * #6. 增强类，编写增强代码实现AOP
 * - 增强类本身要放到IOC容器，需要 @Component 修饰
 * - 增强类要声明为切面使增强方法生效，需要 @Aspect 修饰
 * - 在配置类中，需要开启AspectJ注解，需要 @EnableAspectJAutoProxy 修饰
 *
 * 1. 使用注解配置增强方法，指定插入目标方法的位置
 *      前置   @Before
 *      后置   @AfterReturning
 *      异常   @AfterThrowing
 *      最后   @After
 *      环绕   @Around
 *     相当于
 *       try{
 *           前置
 *           目标方法执行
 *           后置
 *       }catch(){
 *           异常
 *       }finally{
 *           最后
 *       }
 *
 * 2. 配置切点表达式，确定切点，即要插入的方法
 *    固定语法 execution(1 2 3.4.5(6))
 *    1. 访问修饰符，public  / private
 *    2. 方法的返回参数类型，String int void
 *       如果不考虑访问修饰符和返回值! 这两位整合成一起写 *
 *       如果要是不考虑,必须两个都不考虑! 不能出现  * String
 *    3. 包的位置
 *       具体包: com.spring.service.impl
 *       单层模糊: com.spring.service.*   * 单层模糊
 *       多层模糊: com..impl    ..任意层的模糊
 *       细节: ..不能开头
 *       找所有impl包:  com..impl  不能写..impl 写成: *..impl
 *    4. 类的名称
 *       具体: CalculatorPureImpl
 *       模糊: *
 *       部分模糊: *Impl
 *    5. 方法名 语法和类名一致
 *    6. (6)形参数列表
 *       没有参数: ()
 *       有具体参数: (String)  (String,int)
 *       模糊参数: (..) 有没有参数都可以,有多个也可以!
 *       不分模糊: (String..) String 后面有没有无所谓
 *                 (..int)  最后一个参数是int
 *                 (String..int)
 *
 *     实战
 *     1.查询某包某类下，访问修饰符是公有，返回值是int的全部方法
 *       public int xx.xx.jj.*(..)
 *     2.查询某包下类中第一个参数是String的方法
 *       * xx.xx.jj.*(String..)
 *     3.查询全部包下，无参数的方法！
 *        * *..*.*()
 *     4.查询com包下，以int参数类型结尾的方法
 *        * com..*.*(..int)
 *     5.查询指定包下，Service开头类的私有返回值int的无参数方法
 *        private int xx.xx.Service*.*()
 *
 * 3. 切点表达式复用
 * 在 MyPointCut 中定义节点方法，单独维护切点表达式
 * 通过切点类的全限定符号.方法名()在本类中复用execution表达式
 */

@Component
@Aspect
@Order(20)
public class LogAdvice {

    @Before(value = "execution(* spring.aop.service.impl.*.*(..))")
    public void start(){
        System.out.println("方法开始了");
    }

    // TODO：直接调用切点方法实现表达式复用，类的全限定符
    @After("spring.aop.pointcut.MyPointCut.pc()")
    public void after(){
        System.out.println("方法结束了");
    }

    @AfterThrowing("spring.aop.pointcut.MyPointCut.pc()")
    public void error(){
        System.out.println("方法报错了");
    }
}
